package com.googlecode.rulio.rendering.html;

import com.googlecode.rulio.Action;
import com.googlecode.rulio.ExecutionReport;
import com.googlecode.rulio.Rules;
import com.googlecode.rulio.predicates.OfTypePredicate;
import com.googlecode.rulio.rendering.Renderer;
import com.googlecode.totallylazy.Pair;
import com.googlecode.totallylazy.Predicate;
import com.googlecode.totallylazy.Sequence;
import com.googlecode.totallylazy.predicates.AllPredicate;
import com.googlecode.totallylazy.predicates.AndPredicate;

import java.util.ArrayList;
import java.util.List;

import static com.googlecode.rulio.rendering.html.PredicateRenderers.allPredicateRenderer;
import static com.googlecode.rulio.rendering.html.PredicateRenderers.andPredicateRenderer;
import static com.googlecode.rulio.rendering.html.PredicateRenderers.typedInstanceOfRenderer;
import static com.googlecode.rulio.rendering.html.Renderers.*;
import static com.googlecode.totallylazy.Pair.pair;
import static com.googlecode.totallylazy.Predicates.instanceOf;
import static com.googlecode.totallylazy.Sequences.sequence;

class MainRenderer implements Renderer<Object> {
    private List<Pair<? extends Predicate, ? extends Renderer>> renderers = new ArrayList<Pair<? extends Predicate, ? extends Renderer>>();

    public MainRenderer() {
        renderers.add(pair(instanceOf(ExecutionReport.class), executionReportRenderer(this)));
        renderers.add(pair(instanceOf(Rules.class), rulesRenderer()));
        renderers.add(pair(instanceOf(AndPredicate.class), andPredicateRenderer(this)));
        renderers.add(pair(instanceOf(AllPredicate.class), allPredicateRenderer()));
        renderers.add(pair(instanceOf(OfTypePredicate.class), typedInstanceOfRenderer()));
        renderers.add(pair(instanceOf(Action.class), actionRenderer()));
        renderers.add(pair(instanceOf(List.class), listRenderer()));
        renderers.add(pair(instanceOf(Object.class), defaultRenderer()));
    }

    @SuppressWarnings("unchecked")
    public String render(final Object object) {
        Sequence<Pair<? extends Predicate, ? extends Renderer>> sequence = sequence(renderers).filter(new Predicate<Pair<? extends Predicate, ? extends Renderer>>() {
            public boolean matches(Pair<? extends Predicate, ? extends Renderer> pair) {
                return pair.first().matches(object);
            }
        });


        return (sequence.isEmpty()) ? object + "" : sequence.head().second().render(object);
    }
}
